package middleware

import (
	"fmt"
	"github.com/gin-gonic/gin"
	rotatelogs "github.com/lestrrat-go/file-rotatelogs"
	"github.com/rifflock/lfshook"
	"github.com/sirupsen/logrus"
	"math"
	"os"
	"time"
)

// Logger 日志中间件
func Logger() gin.HandlerFunc {
	// 定义输出日志
	filePath := "log/log.log"
	// 指定软连接
	linkName := "latest_log.log"
	// 给定权限
	scr, filePathErr := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0755)
	if filePathErr != nil {
		fmt.Println("file path error:", filePathErr)
	}

	logger := logrus.New()
	// 日志输出位置
	logger.Out = scr
	// 设置日志级别
	logger.SetLevel(logrus.DebugLevel)

	// 设置分割规则
	logWriter, _ := rotatelogs.New(
		"log/log%Y%m%d.log",                       // 根据时间指定文件名
		rotatelogs.WithMaxAge(7*24*time.Hour),     // 保存一周
		rotatelogs.WithRotationTime(24*time.Hour), // 一天分割一次
		rotatelogs.WithLinkName(linkName),         // 指向最新的日志文件，软连接需要权限
	)

	//logWriter := &lumberjack.Logger{
	//	Filename:   "./testlogrus.log",
	//	MaxSize:    500,  // 日志文件大小，单位是 MB
	//	MaxBackups: 3,    // 最大过期日志保留个数
	//	MaxAge:     28,   // 保留过期文件最大时间，单位 天
	//	Compress:   true, // 是否压缩日志，默认是不压缩。这里设置为true，压缩日志
	//}

	// 指定写入的内容
	writeMap := lfshook.WriterMap{
		logrus.InfoLevel:  logWriter,
		logrus.FatalLevel: logWriter,
		logrus.DebugLevel: logWriter,
		logrus.WarnLevel:  logWriter,
		logrus.ErrorLevel: logWriter,
		logrus.PanicLevel: logWriter,
	}
	// 指定日期格式
	hook := lfshook.NewHook(writeMap, &logrus.TextFormatter{
		TimestampFormat: "2006-01-01 15:04:05", // go固定格式，可以按照这个格式输出（据称Golang诞生时间）
	})
	// 分发日志到指定位置
	logger.AddHook(hook)

	return func(c *gin.Context) {

		// 开销时间
		startTime := time.Now()
		c.Next()
		stopTime := time.Since(startTime)
		spendTime := fmt.Sprintf("%d ms", int(math.Ceil(float64(stopTime.Nanoseconds()/1000000.0))))

		hostName, err := os.Hostname()
		if err != nil {
			hostName = "unknown host"
		}
		statusCode := c.Writer.Status()
		clientIp := c.ClientIP()
		userAgent := c.Request.UserAgent()
		dataSize := c.Writer.Size()
		if dataSize < 0 {
			dataSize = 0
		}
		method := c.Request.Method
		path := c.Request.RequestURI

		entry := logger.WithFields(logrus.Fields{
			"HostName":  hostName,   // 主机名
			"status":    statusCode, // 状态
			"SpendTime": spendTime,  // 花费时间
			"Ip":        clientIp,   // 客户端ip
			"Method":    method,     // 请求类型
			"Path":      path,       // 请求地址
			"DataSize":  dataSize,   // 请求数据大小
			"Agent":     userAgent,  // 客户端信息
		})
		// 记录系统内部错误
		if len(c.Errors) > 0 {
			entry.Error(c.Errors.ByType(gin.ErrorTypePrivate).String())
		}
		if statusCode >= 500 {
			entry.Error()
		} else if statusCode >= 400 {
			entry.Warn()
		} else {
			entry.Info()
		}
	}
}
